package net.zoneland.knowledge.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;
import java.util.List;

/**
 * Swagger配置文件
 */
@Configuration
@EnableSwagger2  //开启swagger2
public class SwaggerConfig {

    /**
     * 本地环境profiles名称
     */
    private static final String HZ_LOCAL = "hz-local";
    /**
     * 测试环境profiles名称
     */
    private static final String HZ_TEST = "hz-test";
    /**
     * 请求头
     */
    private static final String PARAMETER_NAME = "请求头";
    /**
     * 请求头参数描述
     */
    private static final String PARAMETER_DESCRIPTION = "JSON Web Token";
    /**
     * swagger扫描包的路径
     */
    private static final String BASE_PACKAGE = "net.zoneland.knowledge.controller";
    /**
     * Authorization
     */
    private static final String AUTHORIZATION = "Authorization";


    /**
     * 创建API应用
     * apiInfo() 增加API相关信息
     * 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现，
     * 本例采用指定扫描的包路径来定义指定要建立API的目录。
     * 多人开发可以设置多个Docket
     * @return 返回
     */
    @Bean
    public Docket createRestApi(final Environment environment) {
        // 设置请求头提示信息
        final ParameterBuilder parameterBuilder = new ParameterBuilder();
        final List<Parameter> parameters = new ArrayList<>();
        parameterBuilder.name(PARAMETER_NAME) // Updates the parameter name
                .description(PARAMETER_DESCRIPTION)
                .modelRef(new ModelRef("string"))
                .parameterType("header")
                .required(false)
                .build();
        parameters.add(parameterBuilder.build());

        // Profiles直接获取环
        final Profiles profiles = Profiles.of(HZ_LOCAL,HZ_TEST);
        // 获取环境，点进源码，查看方法以及参数值
        // 返回值为boolean acceptsProfiles(Profiles var1);boolean类型
        final boolean enable = environment.acceptsProfiles(profiles);

        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(this.apiInfo())
                // false 则不能在浏览器访问，true为默认。
                .enable(enable)
                .select()
                // 配置扫描接口的方式，基于包去扫描
                .apis(RequestHandlerSelectors.basePackage(BASE_PACKAGE))
                // paths()过滤什么路径
                .paths(PathSelectors.any())
                .build()
                // 配置全局token
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts())
                .globalOperationParameters(parameters);
    }

    /**
     * 创建该API的基本信息（这些基本信息会展现在文档页面中）
     * 访问地址：http://项目实际地址/swagger-ui.html
     * @return API的基本信息
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder().title("springboot利用swagger构建api文档")
                .description("党建api文档")
                .version("1.0")
                .build();
    }

    /**
     * 设置基本的介绍信息
     * @return 基本的介绍信息
     */
    private List<ApiKey> securitySchemes() {
        final List<ApiKey> apiKeyList = new ArrayList<>();
        apiKeyList.add(new ApiKey(AUTHORIZATION, AUTHORIZATION, "header"));
        return apiKeyList;
    }

    /**
     * 过滤不需要进行验证的页面
     * @return 过滤信息
     */
    private List<SecurityContext> securityContexts() {
        final List<SecurityContext> securityContexts = new ArrayList<>();
        securityContexts.add(
                SecurityContext.builder()
                        .securityReferences(defaultAuth())
                        //带有auth的页面将不用提供token即可访问。
                        .forPaths(PathSelectors.regex("^(?!auth).*$"))
                        .build());
        return securityContexts;
    }

    /**
     * 全局的token配置
     * @return 全局token配置信息
     */
    private List<SecurityReference> defaultAuth() {
        final AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        final AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        final List<SecurityReference> securityReferences = new ArrayList<>();
        securityReferences.add(new SecurityReference(AUTHORIZATION, authorizationScopes));
        return securityReferences;
    }
}
